﻿using AngryManagementMayhem.Controller.Map;
using AngryManagementMayhem.GameCode.Screens.PlayScreen;
using Transformable_Engine_v2.Engine.Transformable_Math.Geometry;

namespace AngryManagementMayhem.Controller.Player
{
    public abstract partial class Player
    {
        CollisionDefinition.CollisionTypeList ApplyCollision()
        {
            //Handle floor collision
            var rightCollision = GetCollisionRight();
            var leftCollision = GetCollisionLeft();
            var floorCollision = GetCollisionFloor();

            if(rightCollision != null) {
                if(floorCollision != null) {
                    if(rightCollision.CollisionTile.IsEqualTo(floorCollision.CollisionTile)) 
                    {
                        var offset = GetOldPositionCoordinate(floorCollision.Point) - rightCollision.CollisionTile.Position;

                        if(offset.Y <= 0) {
                            ApplyCollision(floorCollision);
                            return CollisionDefinition.CollisionTypeList.Floor;
                        }
                        ApplyCollision(rightCollision);
                        return CollisionDefinition.CollisionTypeList.Right;
                    }
                    ApplyCollision(rightCollision);
                    ApplyCollision(floorCollision);
                    return CollisionDefinition.CollisionTypeList.Floor | CollisionDefinition.CollisionTypeList.Right;
                }
                ApplyCollision(rightCollision);
                return CollisionDefinition.CollisionTypeList.Right;
            }
            if(leftCollision != null) {
                if(floorCollision != null) {
                    if(leftCollision.CollisionTile.IsEqualTo(floorCollision.CollisionTile)) 
                    {
                        var offset = GetOldPositionCoordinate(floorCollision.Point) - leftCollision.CollisionTile.Position;

                        if(offset.Y <= 0) 
                        {
                            ApplyCollision(floorCollision);
                            return CollisionDefinition.CollisionTypeList.Floor;
                        }
                        ApplyCollision(leftCollision);
                        return CollisionDefinition.CollisionTypeList.Left;
                    }
                    ApplyCollision(leftCollision);
                    ApplyCollision(floorCollision);
                    return CollisionDefinition.CollisionTypeList.Floor | CollisionDefinition.CollisionTypeList.Left;
                }
                ApplyCollision(leftCollision);
                return CollisionDefinition.CollisionTypeList.Left;
            }
            if(floorCollision != null) 
            {
                ApplyCollision(floorCollision);
                return CollisionDefinition.CollisionTypeList.Floor;
            }

            return CollisionDefinition.CollisionTypeList.None;
        }

        CollisionDefinition GetCollisionDefinition(int screenX, int screenY, int cellX, int cellY)
        {
            int screenKey = BaseMap.MapLocationToIndex(screenX, screenY);
            int dataKey = BaseScreen.ScreenLocationToIndex(cellX, cellY);

            if(PlayScreen.Map.Screens.ContainsKey(screenKey) && PlayScreen.Map.Screens[screenKey].MapData.ContainsKey(dataKey))
                return PlayScreen.Map.Screens[screenKey].MapData[dataKey];
            return null;
        }

        TE_Vector2 GetOldPositionCoordinate(CollisionDescription.CollisionPoint point)
        {
            switch(point) {
                case CollisionDescription.CollisionPoint.TopLeft:
                    return _oldPosition + _boundingBox.TopLeft;
                case CollisionDescription.CollisionPoint.TopRight:
                    return _oldPosition + _boundingBox.TopRight;
                case CollisionDescription.CollisionPoint.BottomLeft:
                    return _oldPosition + _boundingBox.BottomLeft;
                case CollisionDescription.CollisionPoint.BottomRight:
                    return _oldPosition + _boundingBox.BottomRight;
                case CollisionDescription.CollisionPoint.Bottom:
                    return _oldPosition;
            }

            return null;
        }

        CollisionDescription GetCollisionCeiling()
        {
            var result = HandleCollision(Position + _boundingBox.TopLeft, CollisionDefinition.CollisionTypeList.Ceiling, CollisionDescription.CollisionPoint.TopLeft);

            if(result == null)
                  return HandleCollision(Position + _boundingBox.TopRight, CollisionDefinition.CollisionTypeList.Ceiling, CollisionDescription.CollisionPoint.TopRight);

            return result;
        }

        CollisionDescription GetCollisionRight()
        {
            var result = HandleCollision(Position + _boundingBox.BottomLeft, CollisionDefinition.CollisionTypeList.Right, CollisionDescription.CollisionPoint.BottomLeft);

            if(result == null)
                  return HandleCollision(Position + _boundingBox.TopLeft, CollisionDefinition.CollisionTypeList.Right, CollisionDescription.CollisionPoint.TopLeft);

            return result;
        }

        CollisionDescription GetCollisionLeft()
        {
            var result = HandleCollision(Position + _boundingBox.BottomRight, CollisionDefinition.CollisionTypeList.Left, CollisionDescription.CollisionPoint.BottomRight);
            if(result == null)
                   return HandleCollision(Position + _boundingBox.TopRight, CollisionDefinition.CollisionTypeList.Left, CollisionDescription.CollisionPoint.TopRight);
            return result;
        }

        CollisionDescription GetCollisionFloor()
        {
            var result = HandleCollision(Position + _boundingBox.BottomLeft, CollisionDefinition.CollisionTypeList.Floor, CollisionDescription.CollisionPoint.BottomLeft);

            if(result == null)
                   return HandleCollision(Position + _boundingBox.BottomRight, CollisionDefinition.CollisionTypeList.Floor, CollisionDescription.CollisionPoint.BottomRight);

            return result;
        }

        void ApplyCollision(CollisionDescription positionOffset)
        {
            if(positionOffset != null) 
            {
                Move(positionOffset.CollisionOffset);
            }
        }


        CollisionDescription HandleCollision(TE_Vector2 position, CollisionDefinition.CollisionTypeList type, CollisionDescription.CollisionPoint point)
        {
            var collision = CheckCollision(position);

            if(collision != null && collision.ContainsType(type)) 
            {
                var positionOffset = collision.ResolveCollision(position, _speed + _input.GetDirection(), type);
                if(positionOffset != null) 
                {
                    return new CollisionDescription(positionOffset, collision, point);
                }
                    
            }
            return null;
        }

        CollisionDefinition CheckCollision(TE_Vector2 position)
        {
            int screenX = (int)(position.X / BaseMap.MapSize.X);
            int screenY = (int)(position.Y / BaseMap.MapSize.Y);

            int cellX = (int)((position.X - (screenX * BaseMap.MapSize.X)) / CollisionDefinition.CollisionSize);
            int cellY = (int)((position.Y - (screenY * BaseMap.MapSize.Y)) / CollisionDefinition.CollisionSize);

            return GetCollisionDefinition(screenX, screenY, cellX, cellY);
        }
    }
}